/*
 * ParallelWorkload.hpp
 *
 *  Created on: 18 avr. 2012
 *      Author: jd219546
 */

#ifndef PARALLELWORKLOAD_HPP_
#define PARALLELWORKLOAD_HPP_

#include "tbb/blocked_range.h"
#include "tbb/parallel_do.h"
#include "tbb/parallel_for.h"
#include "tbb/task_scheduler_init.h"

#include "WorkItems.hpp"
#include "Sequence.hpp"

class ParallelWorkload
{
	const Sequence ref_sequence;
	const int minimum_sequence_length;
	const int nb_threads;
	vector<WorkItems::FileReadItem *> files_to_read;

	class ApplyWork {
		const Sequence & ref_sequence;
		const int minimum_sequence_length;
	public:
		ApplyWork(const Sequence & ref_seq, const int min_seq_length):
			ref_sequence(ref_seq),minimum_sequence_length(min_seq_length){};

		//------------------------------------------------------------------------
		// Following signatures are required by parallel_do
		//------------------------------------------------------------------------
		typedef WorkItems::WorkItem* argument_type;

		void operator()( WorkItems::WorkItem* c, tbb::parallel_do_feeder<WorkItems::WorkItem*>& feeder ) const {
			c->execute(feeder, ref_sequence, minimum_sequence_length);
		}
	};

	class ApplyRead
	{
		vector<WorkItems::FileReadItem *> & files_to_read;
		char ** argv;
		public:
			ApplyRead(vector<WorkItems::FileReadItem *> & files_to_read,
					char ** argv)
			:files_to_read(files_to_read),argv(argv)
			{}
			void operator()( const tbb::blocked_range<size_t> & r) const
			{
				for (size_t i = r.begin(); i!= r.end() ; i++)
				{
					cout << "Creating FileReadITem " << i << endl;
					files_to_read[i] = new WorkItems::FileReadItem(argv[i+4], i);
				}
			}
	};

public:
	ParallelWorkload(Sequence ref_seq, int min_common_length, int nb_threads):
		ref_sequence(ref_seq),minimum_sequence_length(min_common_length),nb_threads(nb_threads)
	{
		//tbb::task_scheduler_init init(nb_threads);
	}
	void read_multiple_input_files(char ** argv, int nb_files_to_read)
	{
		files_to_read.resize(nb_files_to_read, 0);
		tbb::parallel_for(
				tbb::blocked_range<size_t>(0,nb_files_to_read),
				ApplyRead(files_to_read, argv));
	}

	void compare_multiple_sequences()
	{
		tbb::parallel_do(files_to_read.begin(), files_to_read.end(),ApplyWork(ref_sequence, minimum_sequence_length));
	}

	void print_solutions() const
	{
		for (vector<WorkItems::FileReadItem *>::const_iterator it = files_to_read.begin();it != files_to_read.end() ; it++)
			(*it)->print_solutions();
	}

};

#endif /* PARALLELWORKLOAD_HPP_ */
